package atom.net 
{
	import atom.error.AtomError;
	import atom.message.Message;
	import atom.message.MessageDispatcher;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.net.ServerSocket;
	import flash.net.Socket;
	import flash.sampler.NewObjectSample;
	
	/**
	 * ...
	 * @author Jorge Braccini
	 */
	public class Link extends EventDispatcher {
		
		private var _host:String;
		private var _port:int;
		private var _socket:Socket;
		private var _io:IOData;
		private var _queue:Array = [];
		private var _dispatcher:MessageDispatcher;
		
		public function Link(host:String, port:int) {
			_io = new IOData(host, port);
			
			init();
		}
		
		//////////////////////////////////////////////////////////
		// Public Methods ////////////////////////////////////////
		//////////////////////////////////////////////////////////
		
		public function get io():IOData { return _io; }
		
		public function connect():void {
			_socket.connect(io.host, io.port);
		}
		
		public function disconnect():void {
			_socket.close();
		}
		
		public function send(message:Message):void {
			if (connected) {
				trace("AtomLink :: send() type: " + message.type);
				_socket.writeUTFBytes(message.toJSON());
				_socket.writeByte(0);
				_socket.flush();
				
			} else _queue.push(message);
		}
		
		public function addListener(type:String, handler:Function):void {
			_dispatcher.addListener(type, handler);
		}
		
		public function removeListener(type:String, handler:Function):void {
			_dispatcher.removeListener(type, handler);
		}
		
		public function get connected():Boolean {
			return _socket.connected;
		}
		
		//////////////////////////////////////////////////////////
		// Private Methods ///////////////////////////////////////
		//////////////////////////////////////////////////////////
		
		private function init():void {
			_dispatcher = new MessageDispatcher();
			_socket = new Socket();
			
			_socket.addEventListener(Event.CONNECT, handleConnect);
			_socket.addEventListener(IOErrorEvent.IO_ERROR, handleError);
			_socket.addEventListener(ProgressEvent.SOCKET_DATA, handleIncoming);
		}
		
		private function error(e:Object):void {
			throw new AtomError(e);
		}
		
		private function handleIncoming(e:ProgressEvent):void {
			trace("AtomLink :: handleIncoming()");
			
			var message:Message = new Message();
				message.parse(_socket.readUTFBytes(e.bytesLoaded));
			
			_dispatcher.dispatchMessage(message);
		}
		
		private function handleConnect(e:Event):void {
			if (_queue.length > 0) {
				while (_queue.length != 0) send(_queue.shift());
			}
			
			dispatchEvent(e);
		}
		
		private function handleError(e:IOErrorEvent):void {
			error(AtomError.SOCKET_NOT_READY);
		}
		
	}

}